package com.whcoding.test.exception;

import com.whcoding.test.constant.ResultStatusEnum;
import com.whcoding.test.pojo.ResponseExceptionVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: spring-boot-learning
 * @description:统一异常 获取controller异常
 * @author: whcoding
 * @create: 2022-06-09 11:01
 **/
@ControllerAdvice
public class GlobalExceptionHandler {
	/**
	 * 添加log信息
	 */
	private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

	/**
	 * 全局处理 {@link org.springframework.web.bind.annotation.RequestParam} 和
	 * {@link org.springframework.web.bind.annotation.PathVariable} 的校验异常
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(ConstraintViolationException.class)
	public ResponseExceptionVO handleConstraintViolationException(ConstraintViolationException e) {
		logger.error(e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.PARAM_FAIL_CODE.getCode(), ResultStatusEnum.PARAM_FAIL_CODE.getMsg());
	}

	/**
	 * 全局处理 {@link org.springframework.web.bind.annotation.RequestBody} 的异常
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	public ResponseExceptionVO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
		BindingResult bindingResult = e.getBindingResult();
		List<String> messageList = bindingResult.getFieldErrors().stream()
				.map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
				.collect(Collectors.toList());
		String resultStr = String.join(", \n", messageList);
		logger.error(resultStr + e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.PARAM_FAIL_CODE.getCode(), e.getBindingResult().getFieldError().getDefaultMessage());
	}

	/**
	 * 多个参数
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(BindException.class)
	public ResponseExceptionVO handlerBindException(BindException e) {
		List<String> messageList = e.getBindingResult().getAllErrors().stream()
				.map(objectError -> objectError.getObjectName() + ": " + objectError.getDefaultMessage())
				.collect(Collectors.toList());

		String resultStr = String.join(", \n", messageList);
		logger.error(resultStr + e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.SYSTEM_ERROR.getCode(), ResultStatusEnum.SYSTEM_ERROR.getMsg());
	}

	/**
	 * ValidationException
	 */
	@ExceptionHandler(ValidationException.class)
	public ResponseExceptionVO handleValidationException(ValidationException e) {
		logger.error(e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.VALIDATION_CODE.getCode(), ResultStatusEnum.VALIDATION_CODE.getMsg());
	}

	/**
	 * 空指针异常
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(NoHandlerFoundException.class)
	public ResponseExceptionVO handlerNoFoundException(Exception e) {
		logger.error(e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.PATH_NOT_FOND.getCode(), ResultStatusEnum.PATH_NOT_FOND.getMsg());
	}

	/**
	 * 违反唯一主键异常
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(DuplicateKeyException.class)
	public ResponseExceptionVO handleDuplicateKeyException(DuplicateKeyException e) {
		logger.error(e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.DUPLICATE_KEY_CODE.getCode(), "数据重复，请检查后提交");
	}


	/**
	 * 捕获 Exception 异常
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(Exception.class)
	public ResponseExceptionVO handleException(Exception e) {
		logger.error(e.getMessage(), e);
		return new ResponseExceptionVO(ResultStatusEnum.DUPLICATE_KEY_CODE.getCode(), "系统繁忙,请稍后再试");
	}

	/**
	 * 上传文件超出最大限制异常
	 * 捕获MaxUploadSizeExceededException 异常
	 *
	 * @param e
	 * @param resp
	 * @throws IOException
	 */
	@ExceptionHandler(MaxUploadSizeExceededException.class)
	public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse resp) throws IOException {
		resp.setContentType("text/html;charset=utf-8");
		System.out.println(1111);
		PrintWriter out = resp.getWriter();
		out.write("上传文件大小超出限制!");
		out.flush();
		out.close();
	}


}

